/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package projetlif13.scene;

import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.newdawn.slick.*;
import org.newdawn.slick.gui.AbstractComponent;
import org.newdawn.slick.gui.ComponentListener;
import org.newdawn.slick.gui.GUIContext;
import org.newdawn.slick.gui.MouseOverArea;
import org.newdawn.slick.particles.ConfigurableEmitter;
import org.newdawn.slick.particles.ParticleIO;
import org.newdawn.slick.particles.ParticleSystem;
import projetlif13.model.Game;
import projetlif13.model.HumanPlayer;
import projetlif13.model.IAPlayer;
import projetlif13.model.Player;
import projetlif13.model.Skin;
import projetlif13.model.puissance4.P4Board;
import projetlif13.model.puissance4.P4Game;
import projetlif13.model.puissance43D.P43DGame;
import projetlif13.model.tictactoe.TicBoard;
import projetlif13.model.tictactoe.TicGame;
import projetlif13.model.tournament.TournamentV2;
import projetlif13.tools.PreferencesBundler;
import projetlif13.view.GameView;

/**
 *
 * @author yohan
 */
public class GameScene extends BasicGame implements ComponentListener {

    public static final int TYPE_P4 = 1;
    public static final int TYPE_TIC = 2;
    public static final int TYPE_P43D = 3;
    public static ArrayList<Skin> skins = new ArrayList<>();
    public static Skin currentpawnskin;
    public static Skin currentboardskin;
    public static GameView gv;
    private int currenttype = -1;
    private int xdisplay = 10;
    private int ydisplay = 10;
    public static Image background;
    public static String backgroundpath;
    private ParticleSystem fireworks;
    /*
     * une seul instance de GameScene, gestion static des images
     */
    public static Sound uiclick;
    public static Sound uitambourine;
    private GameContainer container;
    /*
     * Generic images
     */
    private static Image pawn1;
    private static Image pawn2;
    private static Image slot;
    private static Image slothole;
    /*
     * Skin pawns
     */
    private String redpawnpath = "projetlif13/gfx/pion_rouge.png";
    private static Image redpawn;
    private String bluepawnpath = "projetlif13/gfx/pion_bleu.png";
    private static Image bluepawn;
    private String greenflowerpath = "projetlif13/gfx/fleur_verte.png";
    private static Image greenflower;
    private String magentaflowerpath = "projetlif13/gfx/fleur_violette.png";
    private static Image magentaflower;
    private String mercurypath = "projetlif13/gfx/planet_mercury.png";
    private static Image mercury;
    private String plutopath = "projetlif13/gfx/planet_pluto.png";
    private static Image pluto;
    /*
     * Skins board
     */
    private String slotpath = "projetlif13/gfx/slot.png";
    private static Image slotbase;
    private String slotholepath = "projetlif13/gfx/slot_hole.png";
    private static Image slotbasehole;
    private String slotboispath = "projetlif13/gfx/slot_bois.png";
    private static Image slotbois;
    private String slotboisholepath = "projetlif13/gfx/slot_hole_bois.png";
    private static Image slotboishole;
    private String slotpsychopath = "projetlif13/gfx/slot_psycho.png";
    private static Image slotpsycho;
    private String slotpsychoholepath = "projetlif13/gfx/slot_hole_psycho.png";
    private static Image slotpsychohole;

    /*
     * GUI
     */
    private String uiclickpath = "projetlif13/sfx/uiclick.ogg";
    private String uitambourinepath = "projetlif13/sfx/tambourine.ogg";
    public static String cmde = "";
    volatile Player winner = null;
    volatile boolean draw = false;
    private Thread GameT;
    private Color black = new Color(Color.black);
    private static CopyOnWriteArrayList<SlotComponent> moas = new CopyOnWriteArrayList<>();
    public static int gameType = 1;
    public static int gameBoard = 1;

    public boolean isDraw() {
        return draw;
    }

    public Player getWinner() {
        return winner;
    }

    public void setDraw(boolean draw) {
        this.draw = draw;
    }

    public void setWinner(Player winner) {
        this.winner = winner;
    }

    public GameScene() {
        super("Game by Theo Jonchier & Yohan Bouché");
    }

    @Override
    public void init(GameContainer gc) throws SlickException {
        moas = new CopyOnWriteArrayList<>();
        winner = null;
        draw = false;
        container = gc;
        try {
            /*
             * Particles pour la fin de partie
             */
            fireworks = ParticleIO.loadConfiguredSystem("projetlif13/gfx/fireworks.xml");
        } catch (IOException ex) {
            Logger.getLogger(GameScene.class.getName()).log(Level.SEVERE, null, ex);
        }

        /*
         * Loading base images
         */
        /*
         * PAWNS
         */
        redpawn = new Image(redpawnpath);
        bluepawn = new Image(bluepawnpath);
        greenflower = new Image(greenflowerpath);
        magentaflower = new Image(magentaflowerpath);
        mercury = new Image(mercurypath);
        pluto = new Image(plutopath);
        /*
         * BOARD
         */


        slotbase = new Image(slotpath);
        slotbasehole = new Image(slotholepath);
        slotbois = new Image(slotboispath);
        slotboishole = new Image(slotboisholepath);
        slotpsycho = new Image(slotpsychopath);
        slotpsychohole = new Image(slotpsychoholepath);

        /*
         * Création des skins
         */
        skins.add(new Skin(Skin.SKIN_PAWN, redpawn, bluepawn, slotbase, slotbasehole));
        skins.add(new Skin(Skin.SKIN_FLOWER, greenflower, magentaflower, slotbois, slotboishole));
        skins.add(new Skin(Skin.SKIN_PLANETE, mercury, pluto, slotpsycho, slotpsychohole));

        /*
         * Loading pref files
         */
        PreferencesBundler.load();
        int skinpawn = Integer.parseInt(PreferencesBundler.getValue("skin.pawn", "1"));
        int skinboard = Integer.parseInt(PreferencesBundler.getValue("skin.board", "1"));
        gameBoard = Integer.parseInt(PreferencesBundler.getValue("game.board", "" + Game.TYPE_PVE));
        gameType = Integer.parseInt(PreferencesBundler.getValue("game.type", "" + Game.TYPE_PVE));
        IAPlayer.difficulty = Integer.parseInt(PreferencesBundler.getValue("game.difficulty", "1"));
        backgroundpath = PreferencesBundler.getValue("skin.background", null);
        if (backgroundpath != null && !backgroundpath.equals("")) {
            try {
                background = new Image(backgroundpath);
            } catch (Exception e) {
                System.err.println("fail loading background");
            }//ntd
        }
        System.out.println("skinpawn " + skinpawn + " skinboard " + skinboard);
        System.out.println(skins.toString());

        /*
         * Applying skin
         */
        bindBase(skinpawn, skinboard);


        uiclick = new Sound(uiclickpath);
        uitambourine = new Sound(uitambourinepath);

        uitambourine.play();
        currenttype = (gv.getGame() instanceof P4Game ? TYPE_P4 : gv.getGame() instanceof P43DGame ? TYPE_P43D : TYPE_TIC);

        buildBoard(gv.getGame().getGameBoard().getWidth(), gv.getGame().getGameBoard().getHeight(), gv.getGame().getGameBoard().getDepth(), currenttype);

        GameT = new Thread(new Runnable() {

            @Override
            public void run() {
                winner = gv.getGame().playGame();
                if (winner == null) {
                    draw = true;
                }
            }
        });

        GameT.start();

        System.gc();
    }

    @Override
    public void update(GameContainer gc, int i) throws SlickException {
        if (!draw && winner == null) {
            black.a = 0;
            fireworks.setVisible(false);
        } else if (draw || winner != null) {
            black.a += 0.007f;
            fireworks.setVisible(true);
            ((ConfigurableEmitter) fireworks.getEmitter(0)).setPosition((float) Math.random() * 300, (float) Math.random() * 300);
            ((ConfigurableEmitter) fireworks.getEmitter(1)).setPosition((float) Math.random() * 300, (float) Math.random() * 300);
        }
        fireworks.update(i);

    }

    public void buildBoard(int width, int height, int depth, int type) {

        Image img = (type == TYPE_P4 || type == TYPE_P43D ? slothole : slot);
        xdisplay = 150 - ((img.getWidth() * width) / 2);
        ydisplay = 150 - ((img.getHeight() * height) / 2);
        int x = xdisplay;
        int y = ydisplay;
        int inc3d;
        for (int i = 0; i < width; i++) {
            inc3d = 0;
            for (int j = 0; j < height; j++) {
                if (type == TYPE_P43D) {
                    y = ydisplay + inc3d - (type == TYPE_P43D ? 50 : 0);
                    for (int k = 0; k < depth; k++) {
                        SlotComponent moa = new SlotComponent(container, img, x - 1 + ((k - 1) * 10), y - 2 + ((k - 1) * 10), k, this);
                        moa.setMouseOverColor(Color.lightGray);
                        moa.setMouseDownColor(Color.gray);
                        moa.setXid(i);
                        moa.setYid(j);
                        moas.add(moa);
                        y += 35;

                    }
                    inc3d += 35;

                } else {
                    SlotComponent moa = new SlotComponent(container, img, x - 1, y - 2, 1, this);
                    moa.setMouseOverColor(Color.lightGray);
                    moa.setMouseDownColor(Color.gray);
                    moa.setXid(i);
                    moa.setYid(j);
                    moas.add(moa);
                    y += 35;
                }

            }
            y = ydisplay;
            x += 35;
        }
    }

    @Override
    public void render(GameContainer gc, Graphics grphcs) throws SlickException {

        if (background != null) {
            background.draw(0, 0, 300, 300);
        }
        //pas de gagnant déroulement du jeu
        int x = xdisplay;
        int y = ydisplay;
        int inc3d;
        if (currenttype == TYPE_TIC) {
            for (MouseOverArea b : moas) {
                b.render(container, grphcs);
            }
            for (int i = 0; i < gv.getGame().getGameBoard().getWidth(); i++) {

                for (int j = 0; j < gv.getGame().getGameBoard().getHeight(); j++) {
                    int pidslot = gv.getGame().getGameBoard().getPIDByXY(i, j);
                    if (pidslot % 2 == 0 && pidslot != -1) {
                        pawn2.draw(x - 1, y - 2);
                    } else if (pidslot != -1) {
                        pawn1.draw(x - 1, y - 2);
                    }
                    y += 35;
                }
                y = ydisplay;
                x += 35;
            }
        } else if (currenttype == TYPE_P4) {
            for (int i = 0; i < gv.getGame().getGameBoard().getWidth(); i++) {

                for (int j = 0; j < gv.getGame().getGameBoard().getHeight(); j++) {
                    int pidslot = gv.getGame().getGameBoard().getPIDByXY(i, j);

                    if (pidslot % 2 == 0 && pidslot != -1) {
                        pawn2.draw(x - 1, y - 2);
                    } else if (pidslot != -1) {
                        pawn1.draw(x - 1, y - 2);
                    }

                    y += 35;
                }
                y = ydisplay;
                x += 35;
            }
            for (MouseOverArea b : moas) {
                b.render(container, grphcs);
            }
        } else if (currenttype == TYPE_P43D) {
            for (int i = 0; i < gv.getGame().getGameBoard().getWidth(); i++) {
                inc3d = 0;
                for (int j = 0; j < gv.getGame().getGameBoard().getHeight(); j++) {
                    y = ydisplay + inc3d - 50;
                    for (int z = 0; z < gv.getGame().getGameBoard().getDepth(); z++) {
                        int pidslot = gv.getGame().getGameBoard().getPIDByXYZ(i, j, z);
                        if (pidslot % 2 == 0 && pidslot != -1) {
                            pawn2.setAlpha((1 / (z + 1)));
                            pawn2.draw(x - 1 + ((z - 1) * 10), y - 2 + ((z - 1) * 10));
                            pawn2.setAlpha(1);
                        } else if (pidslot != -1) {
                            pawn1.setAlpha((1 / (z + 1)));
                            pawn1.draw(x - 1 + ((z - 1) * 10), y - 2 + ((z - 1) * 10));
                            pawn1.setAlpha(1);
                        }
                        y += 35;
                    }
                    inc3d += 35;
                }

                x += 35;
            }
            for (MouseOverArea b : moas) {
                b.render(container, grphcs);
            }
        }

        if (TournamentV2.globalWinner != null) {
            //round draw
            Color c = grphcs.getColor();
            grphcs.setColor(black);
            grphcs.fillRect(0, 0, 800, 800);
            grphcs.setColor(c);
            grphcs.drawString("Le grand gagnant du TOURNOIS :\n" + TournamentV2.globalWinner.getName(), 150 - (container.getDefaultFont().getWidth("Le grand gagnant du TOURNOIS :\n" + TournamentV2.globalWinner.getName()) / 2), 150 - container.getDefaultFont().getLineHeight());

        } else {
            if (winner != null) {
                //on a un gagnant
                Color c = grphcs.getColor();
                grphcs.setColor(black);
                grphcs.fillRect(0, 0, 800, 800);
                grphcs.setColor(c);
                grphcs.drawString(winner.getName() + " gagne le match!", 150 - (container.getDefaultFont().getWidth(winner.getName() + " gagne le match!") / 2), 150 - container.getDefaultFont().getLineHeight());

            } else if (draw) {
                //round draw
                Color c = grphcs.getColor();
                grphcs.setColor(black);
                grphcs.fillRect(0, 0, 800, 800);
                grphcs.setColor(c);
                grphcs.drawString("Match nul!", 150 - (container.getDefaultFont().getWidth("Match nul!") / 2), 150 - container.getDefaultFont().getLineHeight());

            }
        }

        grphcs.drawString(gv.getGame().getPlayers()[0].getName(), 0, 0);//nom du j1
        pawn2.draw(container.getDefaultFont().getWidth(gv.getGame().getPlayers()[0].getName()), 0, 0.5f);
        grphcs.drawString(gv.getGame().getPlayers()[1].getName(), 315 - container.getDefaultFont().getWidth(gv.getGame().getPlayers()[1].getName()), 300 - container.getDefaultFont().getLineHeight());//nom du j1
        pawn1.draw(295 - container.getDefaultFont().getWidth(gv.getGame().getPlayers()[1].getName()), 300 - container.getDefaultFont().getLineHeight(), 0.5f);
        fireworks.render();
    }

    public void reinit() {
        cmde = "";
        for (MouseOverArea a : moas) {
            a.removeListener(this);
        }
        container.getInput().removeAllListeners();
        moas.clear();
        System.gc();
        moas = new CopyOnWriteArrayList<>();
        winner = null;
        draw = false;
        currenttype = (gv.getGame() instanceof P4Game ? TYPE_P4 : gv.getGame() instanceof P43DGame ? TYPE_P43D : TYPE_TIC);

        buildBoard(gv.getGame().getGameBoard().getWidth(), gv.getGame().getGameBoard().getHeight(), gv.getGame().getGameBoard().getDepth(), currenttype);

        if (GameT != null) {
            GameT.stop();
            //Permet d'arreter le jeu précédent c'est mal mais ça fonctionne, en attendant de trouver une solution propre dans Game.stop(), un callback?
        }
        GameT = new Thread(new Runnable() {

            @Override
            public void run() {
                winner = gv.getGame().playGame();
                if (winner == null) {
                    draw = true;
                }
                gv.getGame().stop();
            }
        });
        GameT.start();
    }

    @Override
    public void componentActivated(AbstractComponent ac) {
        if (HumanPlayer.canPlay) {
            HumanPlayer.canPlay = false;
            if (ac instanceof SlotComponent) {
                if (currenttype == TYPE_P4) {
                    SlotComponent sc = (SlotComponent) ac;
                    cmde = "" + sc.xid;
                    uiclick.play();
                } else if (currenttype == TYPE_TIC) {
                    SlotComponent sc = (SlotComponent) ac;
                    cmde = "" + sc.xid + "," + sc.yid + ",";
                    uiclick.play();
                } else if (currenttype == TYPE_P43D) {
                    SlotComponent sc = (SlotComponent) ac;
                    cmde = "" + sc.xid + "," + sc.yid + "," + sc.zid + ",";
                    uiclick.play();
                }

            }
        }
    }

    /*
     * Assigne le skin aux images de base
     */
    public static void bindBase(int skinidpawn, int skinidboard) {
        /*
         * search skin by id
         */
        for (Skin s : skins) {
            if (s.getType() == skinidpawn) {
                currentpawnskin = s;
                pawn1 = s.getPawn1();
                pawn2 = s.getPawn2();
            }
            if (s.getType() == skinidboard) {
                currentboardskin = s;
                slot = s.getSlot();
                slothole = s.getSlotHole();
            }

        }
    }
    /*
     * Changement skin des pions + slots sous entendu une premiere partie a été
     * déjà jouée
     */

    public static void changeSkin(int skinidpawn, int skinidboard) {
        bindBase(skinidpawn, skinidboard);
        for (MouseOverArea a : moas) {
            if (gv.getGame() instanceof TicGame) {
                a.setNormalImage(slot);
                a.setMouseOverImage(slot);
                a.setMouseDownImage(slot);
            } else {
                a.setNormalImage(slothole);
                a.setMouseOverImage(slothole);
                a.setMouseDownImage(slothole);
            }
        }
    }

    private class SlotComponent extends MouseOverArea {

        private int xid;
        private int yid;
        private int zid;

        public int getZid() {
            return zid;
        }

        public void setZid(int zid) {
            this.zid = zid;
        }

        public int getXid() {
            return xid;
        }

        public int getYid() {
            return yid;
        }

        public void setXid(int xid) {
            this.xid = xid;
        }

        public void setYid(int yid) {
            this.yid = yid;
        }

        public SlotComponent(GUIContext c, Image img, int x, int y, int z, ComponentListener cl) {
            super(c, img, x, y, cl);
            zid = z;
        }
    }
}
